import * as THREE from "three";
import * as Cesium from "cesium";
import { CSS3DSprite, CSS3DRenderer } from "three/examples/jsm/Addons.js";
import {
  EffectComposer,
  RenderPass,
  UnrealBloomPass,
  GlitchPass,
  ShaderPass,
} from "three/examples/jsm/Addons.js";
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial";

const tianditutkArr = [
  "590447cdbdf97775b57588a69ebb903d",
  // "75f1cc913e8d68f7bd4b6f6383f78ceb",
  "4c4c0f03b0bdb58811f657fec0c09eb5",
];
// ['590447cdbdf97775b57588a69ebb903d', '75f1cc913e8d68f7bd4b6f6383f78ceb', '4c4c0f03b0bdb58811f657fec0c09eb5',
// '67cd2f398449d93fcd47a54e1ea620e3']
const tianditutk =
  tianditutkArr[Math.floor(Math.random() * tianditutkArr.length)];
Cesium.Ion.defaultAccessToken =
  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhZjE5ZTBhZC00YzE1LTQyMWYtOWM4MC00NmFlZjZhOGI3ZDciLCJpZCI6MTI4NTI2LCJpYXQiOjE2OTg4MzczOTN9.26EHXec7Ufty_B4e5_YWcB0t--zlquly7r66WVSS9wE";
// 控制Cesium的默认视角
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(
  108.4,
  21.3,
  129.3,
  48.6
);
export default class TCesium {
  constructor(div, minWGS84, maxWGS84, centerWGS84) {
    this.div = document.getElementById(div);
    this.minWGS84 = minWGS84;
    this.maxWGS84 = maxWGS84;
    this.centerWGS84 = centerWGS84;
    this.cesium = {
      viewer: null,
    };
    this.three = {
      scene: null,
      camera: null,
      renderer: null,
      cssRenderer: null,
      composer: null,
    };
    // cesium的canvas画布映射到three的纹理
    this.texture = null;
    this._3Dobjects = [];
    this.init();
  }
  init() {
    this.initCesium();
    this.initThree();
    this.initObject3d();
    this.bindClick();
  }
  // 创建cesium 地球
  initCesium() {
    this.cesium.viewer = new Cesium.Viewer(this.div, {
      infoBox: false,
      selectionIndicator: false,
      homeButton: false,
      sceneModePicker: false,
      navigationHelpButton: false,
      navigationInstructionsInitiallyVisible: false,
      animation: false,
      timeline: false,
      fullscreenButton: false,
      allowTextureFilterAnisotropic: false,
      baseLayerPicker: false,
      contextOptions: {
        requestWebgl2: true,
        // 默认开启webgl2
        requestWebgl1: false,
        webgl: {
          alpha: false,
          antialias: true,
          preserveDrawingBuffer: true,
          failIfMajorPerformanceCaveat: false,
          depth: true,
          stencil: false,
          anialias: false,
        },
      },
      targetFrameRate: 60,
      resolutionScale: 0.1,
      orderIndependentTranslucency: true,
      //加载底图
      // baseLayer: new Cesium.ImageryLayer(
      //   new Cesium.WebMapTileServiceImageryProvider({
      //     url:
      //       "http://t0.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=" +
      //       tianditutk,
      //     layer: "tdtImgLayer",
      //     style: "default",
      //     format: "image/jpeg",
      //     tileMatrixSetID: "GoogleMapsCompatible", //使用谷歌的瓦片切片方式
      //     show: true,
      //   })
      // ),
      // 开启2.5D视角
      // sceneMode: Cesium.SceneMode.COLUMBUS_VIEW,
      geocoder: false,
      automaticallyTrackDataSourceClocks: false,
      dataSources: null,
      clock: null,
      // 添加地形
      terrain: Cesium.Terrain.fromWorldTerrain(),
      terrainShadows: Cesium.ShadowMode.ENABLED,
      // 添加天空盒
      // skyBox: new Cesium.SkyBox({
      //   sources: {
      //     positiveX: 'park/posx.jpg',
      //     negativeX: 'park/negx.jpg',
      //     positiveY: 'park/posx.jpg',
      //     negativeY: 'park/negx.jpg',
      //     positiveZ: 'park/posy.jpg',
      //     negativeZ: 'park/negy.jpg'
      //   }
      // })
    });
    // 隐藏cesium的canvas
    // this.cesium.viewer.canvas.style.opacity = 0;
    // 得到中心点
    const center = Cesium.Cartesian3.fromDegrees(
      this.centerWGS84
        ? this.centerWGS84[0]
        : (this.minWGS84[0] + this.maxWGS84[0]) / 2,
      this.centerWGS84
        ? this.centerWGS84[1]
        : (this.minWGS84[1] + this.maxWGS84[1]) / 2 - 1,
      500000
    );
    // 开启深度测试，控制视角不转到地下
    this.cesium.viewer.scene.globe.depthTestAgainstTerrain = true;
    // 显示帧率
    this.cesium.viewer.scene.debugShowFramesPerSecond = true;
    // 相机移动到中心点并设置朝向
    // this.cesium.viewer.camera.flyTo({
    //   destination: center,
    //   orientation: {
    //     heading: Cesium.Math.toRadians(0),
    //     pitch: Cesium.Math.toRadians(-60),
    //     roll: Cesium.Math.toRadians(0)
    //   },
    //   duration: 3
    // })
  }
  // 创建three
  initThree() {
    // 根据cesium的canvas画布创建three的canvas纹理
    const canvas = this.cesium.viewer.canvas;
    this.texture = new THREE.CanvasTexture(canvas);
    this.texture.minFilter = THREE.LinearFilter;
    this.texture.magFilter = THREE.LinearFilter;
    this.texture.wrapS = THREE.ClampToEdgeWrapping;
    this.texture.wrapT = THREE.ClampToEdgeWrapping;
    this.texture.colorSpace = THREE.SRGBColorSpace;
    // 创建three的场景
    this.three.scene = new THREE.Scene();
    // this.three.scene.background = this.texture;
    this.three.renderer = new THREE.WebGLRenderer({
      alpha: true,
      antialias: true, // 开启优化抗锯齿
      preserveDrawingBuffer: true, // 开启保留缓存
      // 设置对数深度缓冲区，优化深度冲突问题
      logarithmicDepthBuffer: true, // 当两个面间距小的时候，可以让threejs更容易区分两个面，谁在前，谁在后
    });
    // 新建相机
    this.three.camera = new THREE.PerspectiveCamera(
      75, // 可视角度
      // 宽高比
      document.documentElement.clientWidth /
        document.documentElement.clientHeight,
      1,
      100 * 1000 * 1000
    );
    // 新建控制器
    // 新建渲染器
    this.three.renderer.setSize(window.innerWidth, window.innerHeight);
    this.three.renderer.setPixelRatio(window.devicePixelRatio);
    // 设置背景色为黑色和透明色
    this.three.renderer.setClearColor(0x000000, 0);
    this.three.renderer.domElement.style.position = "absolute";
    this.three.renderer.domElement.style.top = "0";
    this.three.renderer.domElement.style.left = "0";
    // 设置three渲染的canvas画布放置在cesium的canvas画布的上方且不会影响cesium的交互
    this.three.renderer.domElement.style.pointerEvents = "none";
    this.cesium.viewer.cesiumWidget.canvas.parentElement.appendChild(
      this.three.renderer.domElement
    );
    this.three.cssRenderer = new CSS3DRenderer();
    this.three.cssRenderer.setSize(window.innerWidth, window.innerHeight);
    this.three.cssRenderer.domElement.style.position = "absolute";
    this.three.cssRenderer.domElement.style.top = 0;
    this.three.cssRenderer.domElement.style.pointerEvents = "none";
    this.cesium.viewer.cesiumWidget.canvas.parentElement.appendChild(
      this.three.cssRenderer.domElement
    );
    this.three.composer = new EffectComposer(this.three.renderer);
    this.three.composer.addPass(
      new RenderPass(this.three.scene, this.three.camera)
    );
    // this.three.composer.addPass(new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85))
    // this.three.composer.addPass(new GlitchPass())   // 添加恐怖后处理镜头
    // 添加法向纹理合成的特色渲染镜头
    const shaderPass = new ShaderPass({
      uniforms: {
        tDiffuse: { value: null },
        uNormalMap: { value: null },
      },
      vertexShader: `
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
      `,
      fragmentShader: `
      varying vec2 vUv;
      uniform sampler2D tDiffuse;
      uniform sampler2D uNormalMap;
      void main() {
        vec4 color = texture2D(tDiffuse, vUv);
        vec4 normalColor = texture2D(uNormalMap, vUv);
        // 设置光线的角度
        vec3 lightDir = normalize(vec3(-5.0, 5.0, 1.0));
        // 计算光线明亮程度
        float lightIntensity = clamp(dot(normalColor.xyz, lightDir), 0.0, 1.0);
        // 颜色叠加光线明亮程度
        color.xyz += lightIntensity;
        gl_FragColor = color;
      }
      `,
    });
    const normalTexture = new THREE.TextureLoader().load(
      "interfaceNormalMap.png"
    );
    shaderPass.material.uniforms.uNormalMap.value = normalTexture;
    // 创建不可见的地球球体
    const earthRadius = 6378137;
    const earthGeometry = new THREE.SphereGeometry(earthRadius, 64, 64);
    const earthMaterial = new THREE.MeshBasicMaterial({
      color: 0xffffff,
      colorWrite: false,
    });
    const earthMesh = new THREE.Mesh(earthGeometry, earthMaterial);
    this.three.scene.add(earthMesh);
    // 监听cesium相机的变化
    this.cesium.viewer.camera.changed.addEventListener(
      this.updateThreeCamera.bind(this)
    );
    // this.three.composer.addPass(shaderPass)
  }
  // 渲染Cesium
  renderCesium() {
    this.cesium.viewer.render();
  }
  // 渲染Three
  renderThree() {
    // 更新three的纹理
    this.texture.needsUpdate = true;
    // 更新three的相机
    this.updateThreeCamera();

    //设置宽高比例
    let width = this.div.clientWidth;
    let height = this.div.clientHeight;
    this.three.camera.aspect = width / height;
    this.three.camera.updateProjectionMatrix();
    //设置尺寸大小
    this.three.renderer.setSize(width, height);
    this.three.renderer.clear();
    this.three.composer.render(this.three.scene, this.three.camera);
    this.three.cssRenderer.render(this.three.scene, this.three.camera);
  }
  // 同步three的相机
  updateThreeCamera() {
    // 将three相机视野角度与cesium保持一致
    this.three.camera.fov = Cesium.Math.toDegrees(
      this.cesium.viewer.camera.frustum.fovy
    );
    //更新相机的投影矩阵
    this.three.camera.updateProjectionMatrix();
    // 设置相机跟cesium保持一致
    this.three.camera.matrixAutoUpdate = false; //关闭自动更新矩阵
    //复制cesium相机矩阵
    let cvm = this.cesium.viewer.camera.viewMatrix;
    let civm = this.cesium.viewer.camera.inverseViewMatrix;
    // 设置相机的位置
    this.three.camera.position.set(cvm[12], cvm[13], cvm[14]);
    // three相机默认朝向0,0,0
    this.three.camera.lookAt(0, 0, 0);
    // 设置threejs相机矩阵，使用set方法，通过设置行主序矩阵，内部转换为列主序矩阵
    this.three.camera.matrixWorld.set(
      civm[0],
      civm[4],
      civm[8],
      civm[12],
      civm[1],
      civm[5],
      civm[9],
      civm[13],
      civm[2],
      civm[6],
      civm[10],
      civm[14],
      civm[3],
      civm[7],
      civm[11],
      civm[15]
    );

    this.three.camera.matrixWorldInverse.set(
      cvm[0],
      cvm[4],
      cvm[8],
      cvm[12],
      cvm[1],
      cvm[5],
      cvm[9],
      cvm[13],
      cvm[2],
      cvm[6],
      cvm[10],
      cvm[14],
      cvm[3],
      cvm[7],
      cvm[11],
      cvm[15]
    );
  }
  // 创建three 3d物体
  initObject3d() {
    const threeScene = this.three.scene;
    // 创建圆柱体
    const geometry = new THREE.CylinderGeometry(100000, 100000, 500000, 32);
    const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
    const cylinder = new THREE.Mesh(geometry, material);
    this.setMesh(cylinder, 116.4, 30.9, 0, 0, 0, 0);
    // 将圆柱体添加到Three.js场景中
    this.three.scene.add(cylinder);
    this.setMesh(cylinder, 100, 35, 0);

    // 创建立方体
    let box = new THREE.Mesh(
      new THREE.BoxGeometry(200000, 200000, 200000),
      new THREE.MeshBasicMaterial({ color: 0x00ff00 })
    );
    threeScene.add(box);
    this.setMesh(box, 110, 90, 0);
    // 添加3D样条
    const curve = new THREE.CubicBezierCurve3(
      new THREE.Vector3(-100, 0, 0),
      new THREE.Vector3(-50, 150, 0),
      new THREE.Vector3(200, 150, 0),
      new THREE.Vector3(100, 0, 0)
    );
    // 均匀分布的点
    const curvePoints = curve.getPoints(1000);
    // 等距离分布的点
    // const curvePoints = curve.getSpacedPoints(10)
    console.log("弧长是:", curve.getLength());

    const points2 = [];
    curvePoints.forEach((point) => points2.push(point.x, point.y, point.z));
    const curveGeometry2 = new LineGeometry();
    curveGeometry2.setPositions(points2);
    const curveMaterial2 = new LineMaterial({
      linewidth: 5,
      color: "blue",
    });
    curveMaterial2.resolution.set(window.innerWidth, window.innerHeight);
    const sphere = new THREE.Mesh(curveGeometry2, curveMaterial2);
    threeScene.add(sphere);
    this.setMesh(sphere, 110, 0, 3000);
    sphere.scale.set(2000, 2000, 2000);
  }
  // 将three物体添加到地球上面，设置Mesh的位置和姿态
  setMesh(mesh, lon, lat, height, heading = 0, pitch = 0, roll = 0) {
    // 模型所在位置
    let position = Cesium.Cartesian3.fromDegrees(lon, lat, height);
    // 模型的方向
    let hpr = new Cesium.HeadingPitchRoll(
      Cesium.Math.toRadians(heading),
      Cesium.Math.toRadians(pitch),
      Cesium.Math.toRadians(roll)
    );
    // 步骤1：将HPR转换为Cesium四元数
    const cesiumQuaternion = Cesium.Quaternion.fromHeadingPitchRoll(hpr);

    // 步骤2：映射到Three.js四元数
    const threeQuaternion = new THREE.Quaternion(
      cesiumQuaternion._x,
      cesiumQuaternion._y,
      cesiumQuaternion._z,
      cesiumQuaternion._w
    );
    mesh.quaternion.copy(threeQuaternion)
    // 模型矩阵
    let matrix = Cesium.Transforms.headingPitchRollToFixedFrame(position, hpr);
    // 将cesium矩阵转换为threejs矩阵
    let threeMatrix = new THREE.Matrix4();
    threeMatrix.set(
      matrix[0],
      matrix[1],
      matrix[2],
      matrix[3],
      matrix[4],
      matrix[5],
      matrix[6],
      matrix[7],
      matrix[8],
      matrix[9],
      matrix[10],
      matrix[11],
      matrix[12],
      matrix[13],
      matrix[14],
      matrix[15]
    );
    // 将变换后的矩阵应用到mesh上
    // mesh.matrix.copy(threeMatrix);
    // 解构矩阵，更新位置，姿态，缩放
    // threeMatrix.decompose(mesh.position, mesh.quaternion, mesh.scale);
    mesh.position.copy(position);
    console.log("mesh", mesh)
    // mesh.geometry.translate(0, height / 2, 0);
    // let centerHeight = Cesium.Cartesian3.fromDegrees(lon, lat, 1);
    // mesh.lookAt(centerHeight.x, centerHeight.y, centerHeight.z);
    // mesh.rotateX(-Math.PI / 2);
    // mesh.rotateY(Math.PI / 6);
    // mesh.up.set(0, 0, 1);
    // mesh.updateMatrixWorld();
    return mesh;
  }
  // 绑定点击事件
  bindClick() {
    this.cesium.viewer.scene.globe.depthTestAgainstTerrain = true;
    let handler = new Cesium.ScreenSpaceEventHandler(
      this.cesium.viewer.scene.canvas
    );
    handler.setInputAction((pick) => {
      // 获取cesium中点击的物体
      const pickObj = this.cesium.viewer.scene.pick(pick.position);
      console.log(pickObj);
      // 获取three中对应的物体
      const threeObj = this.getThreeClick(pick.position);
      console.log(threeObj);
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  }
  // 获取three中点击的坐标和物体
  getThreeClick(position) {
    const raycaster = new THREE.Raycaster();
    const pointer = new THREE.Vector2();
    const cesiumP = this.cesium.viewer.scene.canvas.getBoundingClientRect();
    const { width, height, top, left } =
      this.three.renderer.domElement.getBoundingClientRect();
    const offsetx = this.three.renderer.domElement.offsetLeft;
    const offsety = this.three.renderer.domElement.offsetTop;
    const x = position.x + cesiumP.x - left + offsetx;
    const y = position.y + cesiumP.y - top + offsety;
    pointer.x = (x / width) * 2 - 1;
    pointer.y = -(y / height) * 2 + 1;
    const clickObjects = this.three.scene.children;
    // 通过摄像机和鼠标位置更新射线
    raycaster.setFromCamera(pointer, this.three.camera);

    // 计算物体和射线的焦点
    const intersects = raycaster.intersectObjects(clickObjects);
    return intersects[0];
  }
  addMesh(mesh, option) {
    // 放大物体
    // mesh.scale.set(2000, 2000, 2000); // 放大
    this.three.scene.add(mesh);
    this.setMesh(mesh, 102.4, 32.9, 0, 0, 0, 0);
  }
}
